package edu.washington.cs.sounddetector.server.database;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.jdo.annotations.Queries;
import javax.jdo.annotations.Query;
import javax.jdo.annotations.Serialized;

import weka.classifiers.Classifier;

/**
 * Database table for saving the weka model for classification of sounds.
 * 
 * @author the.dylan.price@gmail.com
 * 
 */
@PersistenceCapable
@Queries({ @Query(
        name = "QUERY_BY_USER_DETECTOR",
        language = "JDOQL",
        value = "SELECT UNIQUE FROM edu.washington.cs.sounddetector.server.database.Model WHERE userId == :userId && detectorId == :detectorId") })
public class Model
{
    /**
     * Named Query.
     * 
     * @param userId
     *            (String)
     * @param detectorId
     *            (String)
     */
    public static final String QUERY_BY_USER_DETECTOR = "QUERY_BY_USER_DETECTOR";

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.NATIVE)
    private long id;
    private String userId;
    private String detectorId;
    private List<String> attributes;
    @Serialized
    private byte[] classifier;

    public Model(String detectorId, List<String> attributes, Classifier classifier)
    {
        // TODO: change when we implement users
        this.userId = "1";
        this.detectorId = detectorId;
        this.attributes = attributes;
        setClassifier(classifier);
    }

    /**
     * @return the id
     */
    public long getId()
    {
        return id;
    }

    /**
     * @return the userId
     */
    public String getUserId()
    {
        return userId;
    }

    /**
     * @return the detectorId
     */
    public String getDetectorId()
    {
        return detectorId;
    }

    /**
     * @param detectorId
     *            the detectorId to set
     */
    public void setDetectorId(String detectorId)
    {
        this.detectorId = detectorId;
    }

    /**
     * @param userId
     *            the userId to set
     */
    public void setUserId(String userId)
    {
        this.userId = userId;
    }

    /**
     * @return the attributes
     */
    public List<String> getAttributes()
    {
        return attributes;
    }

    /**
     * @param attributes
     *            the attributes to set
     */
    public void setAttributes(List<String> attributes)
    {
        this.attributes = attributes;
    }

    /**
     * @return the classifier
     */
    public Classifier getClassifier()
    {
        try
        {
            ByteArrayInputStream bais = new ByteArrayInputStream(this.classifier);
            ObjectInputStream ois = new ObjectInputStream(bais);
            Classifier classifier = (Classifier) ois.readObject();
            ois.close();
            return classifier;
        }
        catch (IOException e)
        {
            throw new IllegalArgumentException(e);
        }
        catch (ClassNotFoundException e)
        {
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * @param classifier
     *            the classifier to set
     */
    public void setClassifier(Classifier classifier)
    {
        try
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(classifier);
            oos.flush();
            oos.close();
            this.classifier = baos.toByteArray();
        }
        catch (IOException e)
        {
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * Convenience method for executing {@link #QUERY_BY_USER_DETECTOR}.
     */
    public static Model query(PersistenceManager pm, String userId, String detectorId)
    {
        javax.jdo.Query query = pm.newNamedQuery(Model.class, Model.QUERY_BY_USER_DETECTOR);
        Model result = (Model) query.execute(userId, detectorId);
        return result;
    }
}
